home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / DecimalFormat.java < prev    next >
Text File  |  1998-09-22  |  69KB  |  1,631 lines

  1. /*
  2.  * @(#)DecimalFormat.java    1.37 98/07/07
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.text;
  32. import java.util.ResourceBundle;
  33. import java.util.Locale;
  34. import java.io.IOException;
  35. import java.io.ObjectInputStream;
  36. import java.util.Hashtable;
  37.  
  38. /**
  39.  * <code>DecimalFormat</code> is a concrete subclass of <code>NumberFormat</code>
  40.  * for formatting decimal numbers. This class allows for a variety
  41.  * of parameters, and localization to Western, Arabic, or Indic numbers.
  42.  *
  43.  * <p>
  44.  * Normally, you get the proper <code>NumberFormat</code> for a specific
  45.  * locale (including the default locale) using one of <code>NumberFormat</code>'s
  46.  * factory methods such as <code>getInstance</code>. You may then modify it
  47.  * from there (after testing to make sure it is a <code>DecimalFormat</code>,
  48.  * of course!)
  49.  *
  50.  * <p>
  51.  * Either the prefixes or the suffixes must be different for
  52.  * the parse to distinguish positive from negative.
  53.  * Parsing will be unreliable if the digits, thousands or decimal separators
  54.  * are the same, or if any of them occur in the prefixes or suffixes.
  55.  *
  56.  * <p>
  57.  * <strong>Special cases:</strong>
  58.  *
  59.  * <p>
  60.  * <code>NaN</code> is formatted as a single character, typically
  61.  * <code>\\uFFFD</code>.
  62.  *
  63.  * <p>
  64.  * +/-Infinity is formatted as a single character, typically <code>\\u221E</code>,
  65.  * plus the positive and negative pre/suffixes.
  66.  *
  67.  * <p><code>Note:</code> this class is designed for common users; for very
  68.  * large or small numbers, use a format that can express exponential values.
  69.  
  70.  * <p><strong>Example:</strong>
  71.  * <blockquote>
  72.  * <pre>
  73.  * // normally we would have a GUI with a menu for this
  74.  * Locale[] locales = NumberFormat.getAvailableLocales();
  75.  *
  76.  * double myNumber = -1234.56;
  77.  * NumberFormat form;
  78.  *
  79.  * // just for fun, we print out a number with the locale number, currency
  80.  * // and percent format for each locale we can.
  81.  * for (int j = 0; j < 3; ++j) {
  82.  *     System.out.println("FORMAT");
  83.  *     for (int i = 0; i < locales.length; ++i) {
  84.  *         if (locales[i].getCountry().length() == 0) {
  85.  *            // skip language-only
  86.  *            continue;
  87.  *         }
  88.  *         System.out.print(locales[i].getDisplayName());
  89.  *         switch (j) {
  90.  *         default:
  91.  *             form = NumberFormat.getInstance(locales[i]); break;
  92.  *         case 1:
  93.  *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
  94.  *         case 0:
  95.  *             form = NumberFormat.getPercentInstance(locales[i]); break;
  96.  *         }
  97.  *         try {
  98.  *             System.out.print(": " + ((DecimalFormat)form).toPattern()
  99.  *                          + " -> " + form.format(myNumber));
  100.  *         } catch (IllegalArgumentException iae) { }
  101.  *         try {
  102.  *             System.out.println(" -> " + form.parse(form.format(myNumber)));
  103.  *         } catch (ParseException pe) { }
  104.  *     }
  105.  * }
  106.  * </pre>
  107.  * </blockquote>
  108.  * <strong>The following shows the structure of the pattern.</strong>
  109.  * <pre>
  110.  * pattern    := subpattern{;subpattern}
  111.  * subpattern := {prefix}integer{.fraction}{suffix}
  112.  *
  113.  * prefix     := '\\u0000'..'\\uFFFD' - specialCharacters
  114.  * suffix     := '\\u0000'..'\\uFFFD' - specialCharacters
  115.  * integer    := '#'* '0'* '0'
  116.  * fraction   := '0'* '#'*
  117.  *
  118.  * Notation:
  119.  *  X*       0 or more instances of X
  120.  *  (X | Y)  either X or Y.
  121.  *  X..Y     any character from X up to Y, inclusive.
  122.  *  S - T    characters in S, except those in T
  123.  * </pre>
  124.  * The first subpattern is for positive numbers. The second (optional)
  125.  * subpattern is for negative numbers. (In both cases, ',' can occur
  126.  * inside the integer portion--it is just too messy to indicate in BNF.)
  127.  *
  128.  * <p>
  129.  * Here are the special characters used in the parts of the
  130.  * subpattern, with notes on their usage.
  131.  * <pre>
  132.  * Symbol Meaning
  133.  * 0      a digit
  134.  * #      a digit, zero shows as absent
  135.  * .      placeholder for decimal separator
  136.  * ,      placeholder for grouping separator.
  137.  * ;      separates formats.
  138.  * -      default negative prefix.
  139.  * %      multiply by 100 and show as percentage
  140.  * \u2030 multiply by 1000 and show as per mille
  141.  * \u00A4 currency sign; replaced by currency symbol; if
  142.  *        doubled, replaced by international currency symbol.
  143.  *        If present in a pattern, the monetary decimal separator
  144.  *        is used instead of the decimal separator.
  145.  * X      any other characters can be used in the prefix or suffix
  146.  * '      used to quote special characters in a prefix or suffix.
  147.  * </pre>
  148.  * <p><strong>Notes</strong>
  149.  * <p>
  150.  * If there is no explicit negative subpattern, - is prefixed to the
  151.  * positive form. That is, "0.00" alone is equivalent to "0.00;-0.00".
  152.  * <p>
  153.  * Illegal patterns, such as "#.#.#" or mixing '_' and '*' in the
  154.  * same pattern, will cause an <code>IllegalArgumentException</code> to be
  155.  * thrown. From the message of <code>IllegalArgumentException</code>, you can
  156.  * find the place in the string where the error occurred.
  157.  *
  158.  * <p>
  159.  * The grouping separator is commonly used for thousands, but in some
  160.  * countries for ten-thousands. The interval is a constant number of
  161.  * digits between the grouping characters, such as 100,000,000 or 1,0000,0000.
  162.  * If you supply a pattern with multiple grouping characters, the interval
  163.  * between the last one and the end of the integer is the one that is
  164.  * used. So "#,##,###,####" == "######,####" == "##,####,####".
  165.  *
  166.  * <p>
  167.  * When calling DecimalFormat.parse(String, ParsePosition) and parsing
  168.  * fails, a null object will be returned.  The unchanged parse position
  169.  * also reflects that an error has occurred during parsing.  When calling
  170.  * the convenient method DecimalFormat.parse(String) and parsing fails,
  171.  * a ParseException will be thrown.
  172.  * <p>
  173.  *
  174.  * This class only handles localized digits where the 10 digits
  175.  * are contiguous in Unicode, from 0 to 9. Other digits sets
  176.  * (such as superscripts) would need a different subclass.
  177.  *
  178.  * @see          java.util.Format
  179.  * @see          java.util.NumberFormat
  180.  * @see          java.util.ChoiceFormat
  181.  * @version      1.37 07/07/98
  182.  * @author       Mark Davis
  183.  * @author       Alan Liu
  184.  */
  185. /*
  186.  * Requested Features
  187.  * Symbol Meaning
  188.  * $      currency symbol as decimal point
  189.  * à   escapes text
  190.  * \u2030 divide by 1000 and show as per/mil
  191.  */
  192. public class DecimalFormat extends NumberFormat {
  193.  
  194.     /**
  195.      * Create a DecimalFormat using the default pattern and symbols
  196.      * for the default locale. This is a convenient way to obtain a
  197.      * DecimalFormat when internationalization is not the main concern.
  198.      * <p>
  199.      * To obtain standard formats for a given locale, use the factory methods
  200.      * on NumberFormat such as getNumberInstance. These factories will
  201.      * return the most appropriate sub-class of NumberFormat for a given
  202.      * locale.
  203.      * @see java.text.NumberFormat#getInstance
  204.      * @see java.text.NumberFormat#getNumberInstance
  205.      * @see java.text.NumberFormat#getCurrencyInstance
  206.      * @see java.text.NumberFormat#getPercentInstance
  207.      */
  208.     public DecimalFormat() {
  209.     Locale def = Locale.getDefault();
  210.     /* try to get the pattern from the cache */
  211.     String pattern = (String) cachedLocaleData.get(def);
  212.     if (pattern == null) {  /* cache miss */
  213.         // Get the pattern for the default locale.
  214.         ResourceBundle rb = ResourceBundle.getBundle
  215.         ("java.text.resources.LocaleElements", def);
  216.         String[] all = rb.getStringArray("NumberPatterns");
  217.         pattern = all[0];
  218.         /* update cache */
  219.         cachedLocaleData.put(def, pattern);
  220.     }
  221.     
  222.     /* Always applyPattern after the symbols are set */
  223.         this.symbols = new DecimalFormatSymbols( def );
  224.         applyPattern( pattern, false );
  225.     }
  226.  
  227.  
  228.     /**
  229.      * Create a DecimalFormat from the given pattern and the symbols
  230.      * for the default locale. This is a convenient way to obtain a
  231.      * DecimalFormat when internationalization is not the main concern.
  232.      * <p>
  233.      * To obtain standard formats for a given locale, use the factory methods
  234.      * on NumberFormat such as getNumberInstance. These factories will
  235.      * return the most appropriate sub-class of NumberFormat for a given
  236.      * locale.
  237.      * @param pattern A non-localized pattern string.
  238.      * @exception IllegalArgumentException if the given pattern is invalid.
  239.      * @see java.text.NumberFormat#getInstance
  240.      * @see java.text.NumberFormat#getNumberInstance
  241.      * @see java.text.NumberFormat#getCurrencyInstance
  242.      * @see java.text.NumberFormat#getPercentInstance
  243.      */
  244.     public DecimalFormat(String pattern) {
  245.     // Always applyPattern after the symbols are set
  246.         this.symbols = new DecimalFormatSymbols( Locale.getDefault() );
  247.         applyPattern( pattern, false );
  248.     }
  249.  
  250.  
  251.     /**
  252.      * Create a DecimalFormat from the given pattern and symbols.
  253.      * Use this constructor when you need to completely customize the
  254.      * behavior of the format.
  255.      * <p>
  256.      * To obtain standard formats for a given
  257.      * locale, use the factory methods on NumberFormat such as
  258.      * getInstance or getCurrencyInstance. If you need only minor adjustments
  259.      * to a standard format, you can modify the format returned by
  260.      * a NumberFormat factory method.
  261.      * @param pattern a non-localized pattern string
  262.      * @param symbols the set of symbols to be used
  263.      * @exception IllegalArgumentException if the given pattern is invalid
  264.      * @see java.text.NumberFormat#getInstance
  265.      * @see java.text.NumberFormat#getNumberInstance
  266.      * @see java.text.NumberFormat#getCurrencyInstance
  267.      * @see java.text.NumberFormat#getPercentInstance
  268.      * @see java.text.DecimalFormatSymbols
  269.      */
  270.     public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
  271.         // Always applyPattern after the symbols are set
  272.         this.symbols = (DecimalFormatSymbols)symbols.clone();
  273.         applyPattern( pattern, false );
  274.     }
  275.  
  276.  
  277.     // Overrides
  278.     public StringBuffer format(double number, StringBuffer result,
  279.                                FieldPosition fieldPosition)
  280.     {
  281.         fieldPosition.setBeginIndex(0);
  282.         fieldPosition.setEndIndex(0);
  283.  
  284.         if (Double.isNaN(number))
  285.         {
  286.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  287.             fieldPosition.setBeginIndex(result.length());
  288.  
  289.             result.append(symbols.getNaN());
  290.  
  291.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  292.             fieldPosition.setEndIndex(result.length());
  293.  
  294.             return result;
  295.         }
  296.  
  297.         boolean isNegative = (number < 0.0);
  298.         if (isNegative) number = -number;
  299.  
  300.         // Do this BEFORE checking to see if value is infinite!
  301.         if (multiplier != 1) number *= multiplier;
  302.  
  303.         if (Double.isInfinite(number))
  304.         {
  305.             result.append(isNegative ? negativePrefix : positivePrefix);
  306.  
  307.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  308.             fieldPosition.setBeginIndex(result.length());
  309.  
  310.             result.append(symbols.getInfinity());
  311.  
  312.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  313.             fieldPosition.setEndIndex(result.length());
  314.  
  315.             result.append(isNegative ? negativeSuffix : positiveSuffix);
  316.             return result;
  317.         }
  318.  
  319.         // At this point we are guaranteed a nonnegative finite
  320.         // number.
  321.         synchronized(digitList) {
  322.             digitList.set(number, useExponentialNotation ?
  323.                       getMaximumIntegerDigits() + getMaximumFractionDigits() :
  324.                       getMaximumFractionDigits(),
  325.                       !useExponentialNotation);
  326.  
  327.             return subformat(result, fieldPosition, isNegative, false);
  328.         }
  329.     }
  330.  
  331.     public StringBuffer format(long number, StringBuffer result,
  332.                                FieldPosition fieldPosition)
  333.     {
  334.         fieldPosition.setBeginIndex(0);
  335.         fieldPosition.setEndIndex(0);
  336.  
  337.         boolean isNegative = (number < 0);
  338.         if (isNegative) number = -number;
  339.  
  340.         // In general, long values always represent real finite numbers, so
  341.         // we don't have to check for +/- Infinity or NaN.  However, there
  342.         // is one case we have to be careful of:  The multiplier can push
  343.         // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
  344.         // check for this before multiplying, and if it happens we use doubles
  345.         // instead, trading off accuracy for range.
  346.         if (multiplier != 1 && multiplier != 0)
  347.         {
  348.             boolean useDouble = false;
  349.  
  350.             if (number < 0) // This can only happen if number == Long.MIN_VALUE
  351.             {
  352.                 long cutoff = Long.MIN_VALUE / multiplier;
  353.                 useDouble = (number < cutoff);
  354.             }
  355.             else
  356.             {
  357.                 long cutoff = Long.MAX_VALUE / multiplier;
  358.                 useDouble = (number > cutoff);
  359.             }
  360.  
  361.             if (useDouble)
  362.             {
  363.                 double dnumber = (double)(isNegative ? -number : number);
  364.                 return format(dnumber, result, fieldPosition);
  365.             }
  366.         }
  367.  
  368.         number *= multiplier;
  369.         synchronized(digitList) {
  370.             digitList.set(number, useExponentialNotation ?
  371.                       getMaximumIntegerDigits() + getMaximumFractionDigits() : 0);
  372.  
  373.             return subformat(result, fieldPosition, isNegative, true);
  374.         }
  375.     }
  376.  
  377.     /**
  378.      * Complete the formatting of a finite number.  On entry, the digitList must
  379.      * be filled in with the correct digits.
  380.      */
  381.     private StringBuffer subformat(StringBuffer result, FieldPosition fieldPosition,
  382.                    boolean isNegative, boolean isInteger)
  383.     {
  384.         // NOTE: This isn't required anymore because DigitList takes care of this.
  385.         //
  386.         //  // The negative of the exponent represents the number of leading
  387.         //  // zeros between the decimal and the first non-zero digit, for
  388.         //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
  389.         //  // is more than the maximum fraction digits, then we have an underflow
  390.         //  // for the printed representation.  We recognize this here and set
  391.         //  // the DigitList representation to zero in this situation.
  392.         //
  393.         //  if (-digitList.decimalAt >= getMaximumFractionDigits())
  394.         //  {
  395.         //      digitList.count = 0;
  396.         //  }
  397.  
  398.         char zero = symbols.getZeroDigit();
  399.         int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
  400.         char grouping = symbols.getGroupingSeparator();
  401.         char decimal = isCurrencyFormat ?
  402.             symbols.getMonetaryDecimalSeparator() :
  403.             symbols.getDecimalSeparator();
  404.  
  405.         // We only show a negative prefix if we're actually going to display
  406.         // a non-zero value.  If we're going to display a zero value, then
  407.         // we format it using the positive suffix and prefix.
  408.  
  409.         if (digitList.isZero())
  410.         {
  411.             isNegative = false;
  412.             digitList.decimalAt = 0; // Normalize
  413.         }
  414.  
  415.         result.append(isNegative ? negativePrefix : positivePrefix);
  416.  
  417.         if (useExponentialNotation)
  418.         {
  419.             // Record field information for caller.
  420.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  421.             {
  422.                 fieldPosition.setBeginIndex(result.length());
  423.                 fieldPosition.setEndIndex(-1);
  424.             }
  425.             else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  426.             {
  427.                 fieldPosition.setBeginIndex(-1);
  428.             }
  429.  
  430.             // Minimum integer digits are handled in exponential format by
  431.             // adjusting the exponent.  For example, 0.01234 with 3 minimum
  432.             // integer digits is "123.4E-4".
  433.  
  434.             // Maximum integer digits are interpreted as indicating the
  435.             // repeating range.  This is useful for engineering notation, in
  436.             // which the exponent is restricted to a multiple of 3.  For
  437.             // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
  438.             // If maximum integer digits are defined and are larger than
  439.             // minimum integer digits, then minimum integer digits are
  440.             // ignored.
  441.             int exponent = digitList.decimalAt;
  442.             int repeat = getMaximumIntegerDigits();
  443.             if (repeat > 1 &&
  444.             repeat != getMinimumIntegerDigits())
  445.             {
  446.                 // A repeating range is defined; adjust to it as follows.
  447.                 // If repeat == 3, we have 5,4,3=>3; 2,1,0=>0; -1,-2,-3=>-3;
  448.                 // -4,-5-,6=>-6, etc.  Also, the exponent we have here is
  449.                 // off by one from what we expect; that is, it is for the format
  450.                 // 0.MMMMMx10^n.  So we subtract another 1 to get it in range.
  451.                 exponent -= (exponent < 0) ? repeat : 1;
  452.                 exponent = (exponent / repeat) * repeat;
  453.             }
  454.             else
  455.             {
  456.                 // No repeating range is defined; use minimum integer digits.
  457.                 exponent -= getMinimumIntegerDigits();
  458.             }
  459.  
  460.             // We now output a minimum number of digits, and more if there
  461.             // are more digits, up to the maximum number of digits.  We
  462.             // place the decimal point after the "integer" digits, which
  463.             // are the first (decimalAt - exponent) digits.
  464.             int minimumDigits = getMinimumIntegerDigits()
  465.                                 + getMinimumFractionDigits();
  466.             // The number of integer digits is handled specially if the number
  467.             // is zero, since then there may be no digits.
  468.             int integerDigits = digitList.isZero() ? getMinimumIntegerDigits() :
  469.             digitList.decimalAt - exponent;
  470.             int totalDigits = digitList.count;
  471.             if (minimumDigits > totalDigits) totalDigits = minimumDigits;
  472.  
  473.             for (int i=0; i<totalDigits; ++i)
  474.             {
  475.                 if (i == integerDigits)
  476.                 {
  477.                     // Record field information for caller.
  478.                     if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  479.                     fieldPosition.setEndIndex(result.length());
  480.  
  481.                     result.append(decimal);
  482.  
  483.                     // Record field information for caller.
  484.                     if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  485.                     fieldPosition.setBeginIndex(result.length());
  486.                 }
  487.                 result.append((i < digitList.count) ?
  488.                           (char)(digitList.digits[i] + zeroDelta) :
  489.                           zero);
  490.             }
  491.  
  492.             // Record field information
  493.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  494.             {
  495.                 if (fieldPosition.getEndIndex() < 0)
  496.                     fieldPosition.setEndIndex(result.length());
  497.             }
  498.             else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  499.             {
  500.                 if (fieldPosition.getBeginIndex() < 0)
  501.                     fieldPosition.setBeginIndex(result.length());
  502.                 fieldPosition.setEndIndex(result.length());
  503.             }
  504.  
  505.             // The exponent is output using the pattern-specified minimum
  506.             // exponent digits.  There is no maximum limit to the exponent
  507.             // digits, since truncating the exponent would result in an
  508.             // unacceptable inaccuracy.
  509.             result.append(symbols.getExponentialSymbol());
  510.  
  511.             // For zero values, we force the exponent to zero.  We
  512.             // must do this here, and not earlier, because the value
  513.             // is used to determine integer digit count above.
  514.             if (digitList.isZero()) exponent = 0;
  515.  
  516.             boolean negativeExponent = exponent < 0;
  517.             if (negativeExponent) exponent = -exponent;
  518.             result.append(negativeExponent ? negativePrefix : positivePrefix);
  519.             digitList.set(exponent);
  520.             for (int i=digitList.decimalAt; i<minExponentDigits; ++i) result.append(zero);
  521.             for (int i=0; i<digitList.decimalAt; ++i)
  522.             {
  523.                 result.append((i < digitList.count) ?
  524.                           (char)(digitList.digits[i] + zeroDelta) : zero);
  525.             }
  526.             result.append(negativeExponent ? negativeSuffix : positiveSuffix);
  527.         }
  528.         else
  529.         {
  530.             // Record field information for caller.
  531.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  532.                 fieldPosition.setBeginIndex(result.length());
  533.  
  534.             // Output the integer portion.  Here 'count' is the total
  535.             // number of integer digits we will display, including both
  536.             // leading zeros required to satisfy getMinimumIntegerDigits,
  537.             // and actual digits present in the number.
  538.             int count = getMinimumIntegerDigits();
  539.             int digitIndex = 0; // Index into digitList.fDigits[]
  540.             if (digitList.decimalAt > 0 && count < digitList.decimalAt)
  541.                 count = digitList.decimalAt;
  542.  
  543.             // Handle the case where getMaximumIntegerDigits() is smaller
  544.             // than the real number of integer digits.  If this is so, we
  545.             // output the least significant max integer digits.  For example,
  546.             // the value 1997 printed with 2 max integer digits is just "97".
  547.  
  548.             if (count > getMaximumIntegerDigits())
  549.             {
  550.                 count = getMaximumIntegerDigits();
  551.                 digitIndex = digitList.decimalAt - count;
  552.             }
  553.  
  554.             int sizeBeforeIntegerPart = result.length();
  555.             for (int i=count-1; i>=0; --i)
  556.             {
  557.                 if (i < digitList.decimalAt && digitIndex < digitList.count)
  558.                 {
  559.                     // Output a real digit
  560.                     result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
  561.                 }
  562.                 else
  563.                 {
  564.                     // Output a leading zero
  565.                     result.append(zero);
  566.                 }
  567.  
  568.                 // Output grouping separator if necessary.  Don't output a
  569.                 // grouping separator if i==0 though; that's at the end of
  570.                 // the integer part.
  571.                 if (isGroupingUsed() && i>0 && (groupingSize != 0) && (i % groupingSize == 0))
  572.                 {
  573.                     result.append(grouping);
  574.                 }
  575.             }
  576.  
  577.             // Record field information for caller.
  578.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  579.             fieldPosition.setEndIndex(result.length());
  580.  
  581.             // Determine whether or not there are any printable fractional
  582.             // digits.  If we've used up the digits we know there aren't.
  583.             boolean fractionPresent = (getMinimumFractionDigits() > 0) ||
  584.             (!isInteger && digitIndex < digitList.count);
  585.  
  586.             // If there is no fraction present, and we haven't printed any
  587.             // integer digits, then print a zero.  Otherwise we won't print
  588.             // _any_ digits, and we won't be able to parse this string.
  589.             if (!fractionPresent && result.length() == sizeBeforeIntegerPart)
  590.                 result.append(zero);
  591.  
  592.             // Output the decimal separator if we always do so.
  593.             if (decimalSeparatorAlwaysShown || fractionPresent)
  594.                 result.append(decimal);
  595.  
  596.             // Record field information for caller.
  597.             if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  598.                 fieldPosition.setBeginIndex(result.length());
  599.  
  600.             for (int i=0; i < getMaximumFractionDigits(); ++i)
  601.             {
  602.                 // Here is where we escape from the loop.  We escape if we've output
  603.                 // the maximum fraction digits (specified in the for expression above).
  604.                 // We also stop when we've output the minimum digits and either:
  605.                 // we have an integer, so there is no fractional stuff to display,
  606.                 // or we're out of significant digits.
  607.                 if (i >= getMinimumFractionDigits() &&
  608.                     (isInteger || digitIndex >= digitList.count))
  609.                     break;
  610.  
  611.                 // Output leading fractional zeros.  These are zeros that come after
  612.                 // the decimal but before any significant digits.  These are only
  613.                 // output if abs(number being formatted) < 1.0.
  614.                 if (-1-i > (digitList.decimalAt-1))
  615.                 {
  616.                     result.append(zero);
  617.                     continue;
  618.                 }
  619.  
  620.                 // Output a digit, if we have any precision left, or a
  621.                 // zero if we don't.  We don't want to output noise digits.
  622.                 if (!isInteger && digitIndex < digitList.count)
  623.                 {
  624.                     result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
  625.                 }
  626.                 else
  627.                 {
  628.                     result.append(zero);
  629.                 }
  630.             }
  631.  
  632.             // Record field information for caller.
  633.             if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  634.             fieldPosition.setEndIndex(result.length());
  635.         }
  636.  
  637.         result.append(isNegative ? negativeSuffix : positiveSuffix);
  638.  
  639.         return result;
  640.     }
  641.  
  642.     public Number parse(String text, ParsePosition parsePosition)
  643.     {
  644.         // special case NaN
  645.         if (text.regionMatches(parsePosition.index, symbols.getNaN(),
  646.                    0, symbols.getNaN().length())) {
  647.             parsePosition.index = parsePosition.index + symbols.getNaN().length();
  648.             return new Double(Double.NaN);
  649.         }
  650.  
  651.         boolean[] status = new boolean[STATUS_LENGTH];
  652.  
  653.         if (!subparse(text, parsePosition, digitList, false, status))
  654.             return null;
  655.  
  656.         double  doubleResult = 0.0;
  657.         long    longResult = 0;
  658.         boolean gotDouble = true;
  659.  
  660.         // Finally, have DigitList parse the digits into a value.
  661.         if (status[STATUS_INFINITE])
  662.         {
  663.             doubleResult = Double.POSITIVE_INFINITY;
  664.         }
  665.         else if (digitList.fitsIntoLong(status[STATUS_POSITIVE]))
  666.         {
  667.             gotDouble = false;
  668.             longResult = digitList.getLong();
  669.         }
  670.         else doubleResult = digitList.getDouble();
  671.  
  672.     // return final value
  673.         if (multiplier != 1)
  674.         {
  675.             if (gotDouble)
  676.                 doubleResult /= multiplier;
  677.             else {
  678.                 doubleResult = ((double)longResult) / multiplier;
  679.                 if (doubleResult < 0) doubleResult = -doubleResult;
  680.             }
  681.         }
  682.  
  683.         if (!status[STATUS_POSITIVE])
  684.         {
  685.             doubleResult = -doubleResult;
  686.             longResult = -longResult;
  687.         }
  688.         // At this point, if we divided the result by the multiplier, the result may
  689.         // fit into a long.  We check for this case and return a long if possible.
  690.         // We must do this AFTER applying the negative (if appropriate) in order to
  691.         // handle the case of LONG_MIN; otherwise, if we do this with a positive value
  692.         // -LONG_MIN, the double is > 0, but the long is < 0.  This is a C++-specific
  693.         // situation.
  694.         if (multiplier != 1)
  695.         {
  696.             longResult = (long)doubleResult;
  697.             gotDouble = (doubleResult != (double)longResult);
  698.         }
  699.  
  700.         return gotDouble ? (Number)new Double(doubleResult) : (Number)new Long(longResult);
  701.     }
  702.  
  703.     private static final int STATUS_INFINITE = 0;
  704.     private static final int STATUS_POSITIVE = 1;
  705.     private static final int STATUS_LENGTH   = 2;
  706.  
  707.     /**
  708.      * Parse the given text into a number.  The text is parsed beginning at
  709.      * parsePosition, until an unparseable character is seen.
  710.      * @param text The string to parse.
  711.      * @param parsePosition The position at which to being parsing.  Upon
  712.      * return, the first unparseable character.
  713.      * @param digits The DigitList to set to the parsed value.
  714.      * @param isExponent If true, parse an exponent.  This means no
  715.      * infinite values and integer only.
  716.      * @param status Upon return contains boolean status flags indicating
  717.      * whether the value was infinite and whether it was positive.
  718.      */
  719.     private final boolean subparse(String text, ParsePosition parsePosition,
  720.                    DigitList digits, boolean isExponent,
  721.                    boolean status[])
  722.     {
  723.         int position = parsePosition.index;
  724.         int backup;
  725.  
  726.         // check for positivePrefix; take longest
  727.         boolean gotPositive = text.regionMatches(position,positivePrefix,0,
  728.                                                  positivePrefix.length());
  729.         boolean gotNegative = text.regionMatches(position,negativePrefix,0,
  730.                                                  negativePrefix.length());
  731.         if (gotPositive && gotNegative) {
  732.             if (positivePrefix.length() > negativePrefix.length())
  733.                 gotNegative = false;
  734.             else if (positivePrefix.length() < negativePrefix.length())
  735.                 gotPositive = false;
  736.         }
  737.         if (gotPositive) position += positivePrefix.length();
  738.         else if (gotNegative) position += negativePrefix.length();
  739.         else return false;
  740.  
  741.         // process digits or Inf, find decimal position
  742.         status[STATUS_INFINITE] = false;
  743.         if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
  744.                           symbols.getInfinity().length()))
  745.         {
  746.             position += symbols.getInfinity().length();
  747.             status[STATUS_INFINITE] = true;
  748.         } else {
  749.             // We now have a string of digits, possibly with grouping symbols,
  750.             // and decimal points.  We want to process these into a DigitList.
  751.             // We don't want to put a bunch of leading zeros into the DigitList
  752.             // though, so we keep track of the location of the decimal point,
  753.             // put only significant digits into the DigitList, and adjust the
  754.             // exponent as needed.
  755.  
  756.             digits.decimalAt = digits.count = 0;
  757.             char zero = symbols.getZeroDigit();
  758.             char nine = (char)(zero + 9);
  759.             int zeroDelta = '0' - zero;
  760.             char decimal = isCurrencyFormat ?
  761.             symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator();
  762.             char grouping = symbols.getGroupingSeparator();
  763.             char exponentChar = symbols.getExponentialSymbol();
  764.             boolean sawDecimal = false;
  765.             boolean sawExponent = false;
  766.             int exponent = 0; // Set to the exponent value, if any
  767.  
  768.             // We have to track digitCount ourselves, because digits.count will
  769.             // pin when the maximum allowable digits is reached.
  770.             int digitCount = 0;
  771.  
  772.             backup = -1;
  773.             for (; position < text.length(); ++position)
  774.             {
  775.                 char ch = text.charAt(position);
  776.                 if (ch == zero)
  777.                 {
  778.                     // Cancel out backup setting (see grouping handler below)
  779.                     backup = -1; // Do this BEFORE continue statement below!!!
  780.  
  781.                     // Handle leading zeros
  782.                     if (digits.count == 0)
  783.                     {
  784.                         // Ignore leading zeros in integer part of number.
  785.                         if (!sawDecimal) continue;
  786.  
  787.                         // If we have seen the decimal, but no significant digits yet,
  788.                         // then we account for leading zeros by decrementing the
  789.                         // digits.decimalAt into negative values.
  790.                         --digits.decimalAt;
  791.                     }
  792.                     else
  793.                     {
  794.                         ++digitCount;
  795.                         digits.append((char)(ch + zeroDelta));
  796.                     }
  797.                 }
  798.                 else if (ch > zero && ch <= nine)
  799.                 {
  800.                     ++digitCount;
  801.                     digits.append((char)(ch + zeroDelta));
  802.  
  803.                     // Cancel out backup setting (see grouping handler below)
  804.                     backup = -1;
  805.                 }
  806.                 else if (!isExponent && ch == decimal)
  807.                 {
  808.                     // If we're only parsing integers, or if we ALREADY saw the
  809.                     // decimal, then don't parse this one.
  810.                     if (isParseIntegerOnly() || sawDecimal) break;
  811.                     digits.decimalAt = digitCount; // Not digits.count!
  812.                     sawDecimal = true;
  813.                 }
  814.                 else if (!isExponent && ch == grouping && isGroupingUsed())
  815.                 {
  816.                     // Ignore grouping characters, if we are using them, but require
  817.                     // that they be followed by a digit.  Otherwise we backup and
  818.                     // reprocess them.
  819.                     backup = position;
  820.                 }
  821.                 else if (!isExponent && ch == exponentChar && !sawExponent)
  822.                 {
  823.                     // Process the exponent by recursively calling this method.
  824.                     ParsePosition pos = new ParsePosition(position + 1);
  825.                     boolean[] stat = new boolean[STATUS_LENGTH];
  826.                     DigitList exponentDigits = new DigitList();
  827.  
  828.                     if (subparse(text, pos, exponentDigits, true, stat) &&
  829.                     exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE]))
  830.                     {
  831.                     position = pos.index; // Advance past the exponent
  832.                     exponent = (int)exponentDigits.getLong();
  833.                     if (!stat[STATUS_POSITIVE]) exponent = -exponent;
  834.                     sawExponent = true;
  835.                     }
  836.                     break; // Whether we fail or succeed, we exit this loop
  837.                 }
  838.                 else break;
  839.             }
  840.  
  841.             if (backup != -1) position = backup;
  842.  
  843.             // If there was no decimal point we have an integer
  844.             if (!sawDecimal) digits.decimalAt = digitCount; // Not digits.count!
  845.  
  846.             // Adjust for exponent, if any
  847.             digits.decimalAt += exponent;
  848.         }
  849.  
  850.         // check for positiveSuffix
  851.         if (gotPositive)
  852.             gotPositive = text.regionMatches(position,positiveSuffix,0,
  853.                                              positiveSuffix.length());
  854.         if (gotNegative)
  855.             gotNegative = text.regionMatches(position,negativeSuffix,0,
  856.                                              negativeSuffix.length());
  857.  
  858.         // if both match, take longest
  859.         if (gotPositive && gotNegative) {
  860.             if (positiveSuffix.length() > negativeSuffix.length())
  861.                 gotNegative = false;
  862.             else if (positiveSuffix.length() < negativeSuffix.length())
  863.                 gotPositive = false;
  864.         }
  865.  
  866.         // fail if neither or both
  867.         if (gotPositive == gotNegative) return false;
  868.  
  869.         parsePosition.index = position +
  870.             (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
  871.  
  872.         status[STATUS_POSITIVE] = gotPositive;
  873.  
  874.         return true;
  875.     }
  876.  
  877.     /**
  878.      * Returns the decimal format symbols, which is generally not changed
  879.      * by the programmer or user.
  880.      * @return desired DecimalFormatSymbols
  881.      * @see java.util.DecimalFormatSymbols
  882.      */
  883.     public DecimalFormatSymbols getDecimalFormatSymbols() {
  884.         try {
  885.             // don't allow multiple references
  886.             return (DecimalFormatSymbols) symbols.clone();
  887.         } catch (Exception foo) {
  888.             return null; // should never happen
  889.         }
  890.     }
  891.  
  892.  
  893.     /**
  894.      * Sets the decimal format symbols, which is generally not changed
  895.      * by the programmer or user.
  896.      * @param newSymbols desired DecimalFormatSymbols
  897.      * @see java.util.DecimalFormatSymbols
  898.      */
  899.     public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
  900.         try {
  901.             // don't allow multiple references
  902.             symbols = (DecimalFormatSymbols) newSymbols.clone();
  903.         } catch (Exception foo) {
  904.             // should never happen
  905.         }
  906.     }
  907.  
  908.     /**
  909.      * Get the positive prefix.
  910.      * <P>Examples: +123, $123, sFr123
  911.      */
  912.     public String getPositivePrefix () {
  913.         return positivePrefix;
  914.     }
  915.  
  916.     /**
  917.      * Set the positive prefix.
  918.      * <P>Examples: +123, $123, sFr123
  919.      */
  920.     public void setPositivePrefix (String newValue) {
  921.         positivePrefix = newValue;
  922.     }
  923.  
  924.     /**
  925.      * Get the negative prefix.
  926.      * <P>Examples: -123, ($123) (with negative suffix), sFr-123
  927.      */
  928.     public String getNegativePrefix () {
  929.         return negativePrefix;
  930.     }
  931.  
  932.     /**
  933.      * Set the negative prefix.
  934.      * <P>Examples: -123, ($123) (with negative suffix), sFr-123
  935.      */
  936.     public void setNegativePrefix (String newValue) {
  937.         negativePrefix = newValue;
  938.     }
  939.  
  940.     /**
  941.      * Get the positive suffix.
  942.      * <P>Example: 123%
  943.      */
  944.     public String getPositiveSuffix () {
  945.         return positiveSuffix;
  946.     }
  947.  
  948.     /**
  949.      * Set the positive suffix.
  950.      * <P>Example: 123%
  951.      */
  952.     public void setPositiveSuffix (String newValue) {
  953.         positiveSuffix = newValue;
  954.     }
  955.  
  956.     /**
  957.      * Get the negative suffix.
  958.      * <P>Examples: -123%, ($123) (with positive suffixes)
  959.      */
  960.     public String getNegativeSuffix () {
  961.         return negativeSuffix;
  962.     }
  963.  
  964.     /**
  965.      * Set the positive suffix.
  966.      * <P>Examples: 123%
  967.      */
  968.     public void setNegativeSuffix (String newValue) {
  969.         negativeSuffix = newValue;
  970.     }
  971.  
  972.     /**
  973.      * Get the multiplier for use in percent, permill, etc.
  974.      * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
  975.      * (For Arabic, use arabic percent symbol).
  976.      * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
  977.      * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
  978.      */
  979.     public int getMultiplier () {
  980.         return multiplier;
  981.     }
  982.  
  983.     /**
  984.      * Set the multiplier for use in percent, permill, etc.
  985.      * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
  986.      * (For Arabic, use arabic percent symbol).
  987.      * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
  988.      * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
  989.      */
  990.     public void setMultiplier (int newValue) {
  991.         multiplier = newValue;
  992.     }
  993.  
  994.     /**
  995.      * Return the grouping size. Grouping size is the number of digits between
  996.      * grouping separators in the integer portion of a number.  For example,
  997.      * in the number "123,456.78", the grouping size is 3.
  998.      * @see #setGroupingSize
  999.      * @see java.text.NumberFormat#isGroupingUsed
  1000.      * @see java.text.DecimalFormatSymbols#getGroupingSeparator
  1001.      */
  1002.     public int getGroupingSize () {
  1003.         return groupingSize;
  1004.     }
  1005.  
  1006.     /**
  1007.      * Set the grouping size. Grouping size is the number of digits between
  1008.      * grouping separators in the integer portion of a number.  For example,
  1009.      * in the number "123,456.78", the grouping size is 3.
  1010.      * @see #getGroupingSize
  1011.      * @see java.text.NumberFormat#setGroupingUsed
  1012.      * @see java.text.DecimalFormatSymbols#setGroupingSeparator
  1013.      */
  1014.     public void setGroupingSize (int newValue) {
  1015.         groupingSize = (byte)newValue;
  1016.     }
  1017.  
  1018.     /**
  1019.      * Allows you to get the behavior of the decimal separator with integers.
  1020.      * (The decimal separator will always appear with decimals.)
  1021.      * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
  1022.      */
  1023.     public boolean isDecimalSeparatorAlwaysShown() {
  1024.         return decimalSeparatorAlwaysShown;
  1025.     }
  1026.  
  1027.     /**
  1028.      * Allows you to set the behavior of the decimal separator with integers.
  1029.      * (The decimal separator will always appear with decimals.)
  1030.      * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
  1031.      */
  1032.     public void setDecimalSeparatorAlwaysShown(boolean newValue) {
  1033.         decimalSeparatorAlwaysShown = newValue;
  1034.     }
  1035.  
  1036.     /**
  1037.      * Standard override; no change in semantics.
  1038.      */
  1039.     public Object clone() {
  1040.         try {
  1041.             DecimalFormat other = (DecimalFormat) super.clone();
  1042.             other.symbols = (DecimalFormatSymbols) symbols.clone();
  1043.             return other;
  1044.         } catch (Exception e) {
  1045.             throw new InternalError();
  1046.         }
  1047.     };
  1048.  
  1049.     /**
  1050.      * Overrides equals
  1051.      */
  1052.     public boolean equals(Object obj)
  1053.     {
  1054.         if (obj == null) return false;
  1055.         if (!super.equals(obj)) return false; // super does class check
  1056.         DecimalFormat other = (DecimalFormat) obj;
  1057.         return (positivePrefix.equals(other.positivePrefix)
  1058.             && positiveSuffix.equals(other.positiveSuffix)
  1059.             && negativePrefix.equals(other.negativePrefix)
  1060.             && negativeSuffix.equals(other.negativeSuffix)
  1061.             && multiplier == other.multiplier
  1062.             && groupingSize == other.groupingSize
  1063.             && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
  1064.             && useExponentialNotation == other.useExponentialNotation
  1065.             && (!useExponentialNotation ||
  1066.                 minExponentDigits == other.minExponentDigits)
  1067.             && symbols.equals(other.symbols));
  1068.     }
  1069.  
  1070.     /**
  1071.      * Overrides hashCode
  1072.      */
  1073.     public int hashCode() {
  1074.         return super.hashCode() * 37 + positivePrefix.hashCode();
  1075.         // just enough fields for a reasonable distribution
  1076.     }
  1077.  
  1078.     /**
  1079.      * Synthesizes a pattern string that represents the current state
  1080.      * of this Format object.
  1081.      * @see #applyPattern
  1082.      */
  1083.     public String toPattern() {
  1084.         return toPattern( false );
  1085.     }
  1086.  
  1087.     /**
  1088.      * Synthesizes a localized pattern string that represents the current
  1089.      * state of this Format object.
  1090.      * @see #applyPattern
  1091.      */
  1092.     public String toLocalizedPattern() {
  1093.         return toPattern( true );
  1094.     }
  1095.  
  1096.     /**
  1097.      * Does the real work of generating a pattern.
  1098.      */
  1099.     private String toPattern(boolean localized) {
  1100.         StringBuffer result = new StringBuffer();
  1101.         for (int j = 1; j >= 0; --j) {
  1102.             if (j == 1)
  1103.                 result.append(positivePrefix);
  1104.             else result.append(negativePrefix);
  1105.         int i;
  1106.         if (useExponentialNotation)
  1107.         {
  1108.             for (i = getMaximumIntegerDigits(); i > 0; --i)
  1109.             {
  1110.                 if (i == groupingSize)
  1111.                     result.append(localized ? symbols.getGroupingSeparator() :
  1112.                                   PATTERN_GROUPING_SEPARATOR);
  1113.                 if (i <= getMinimumIntegerDigits())
  1114.                     result.append(localized ? symbols.getZeroDigit() :
  1115.                                   PATTERN_ZERO_DIGIT);
  1116.                 else
  1117.                     result.append(localized ? symbols.getDigit() :
  1118.                                   PATTERN_DIGIT);
  1119.                 
  1120.             }
  1121.         }
  1122.         else
  1123.         {
  1124.         int tempMax = Math.max(groupingSize, getMinimumIntegerDigits())+1;
  1125.         for (i = tempMax; i > 0; --i) {
  1126.             if (i == groupingSize)
  1127.             result.append(localized ? symbols.getGroupingSeparator() :
  1128.                       PATTERN_GROUPING_SEPARATOR);
  1129.             if (i <= getMinimumIntegerDigits()) {
  1130.             result.append(localized ? symbols.getZeroDigit() :
  1131.                       PATTERN_ZERO_DIGIT);
  1132.             } else {
  1133.             result.append(localized ? symbols.getDigit() :
  1134.                       PATTERN_DIGIT);
  1135.             }
  1136.         }
  1137.             }
  1138.             if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
  1139.                 result.append(localized ? symbols.getDecimalSeparator() :
  1140.                               PATTERN_DECIMAL_SEPARATOR);
  1141.             for (i = 0; i < getMaximumFractionDigits(); ++i) {
  1142.                 if (i < getMinimumFractionDigits()) {
  1143.                     result.append(localized ? symbols.getZeroDigit() :
  1144.                                   PATTERN_ZERO_DIGIT);
  1145.                 } else {
  1146.                     result.append(localized ? symbols.getDigit() :
  1147.                                   PATTERN_DIGIT);
  1148.                 }
  1149.             }
  1150.         if (useExponentialNotation)
  1151.         {
  1152.         result.append(localized ? symbols.getExponentialSymbol() :
  1153.                   PATTERN_EXPONENT);
  1154.         for (i=0; i<minExponentDigits; ++i)
  1155.                     result.append(localized ? symbols.getZeroDigit() :
  1156.                                   PATTERN_ZERO_DIGIT);
  1157.         }
  1158.             if (j == 1) {
  1159.                 result.append(positiveSuffix);
  1160.                 if (negativeSuffix.equals(positiveSuffix)) {
  1161.                     if (negativePrefix.equals(symbols.getMinusSign() + positivePrefix))
  1162.                         break;
  1163.                 }
  1164.                 result.append(localized ? symbols.getPatternSeparator() :
  1165.                               PATTERN_SEPARATOR);
  1166.             } else result.append(negativeSuffix);
  1167.         }
  1168.         return result.toString();
  1169.     }
  1170.  
  1171.  
  1172.     /**
  1173.      * Apply the given pattern to this Format object.  A pattern is a
  1174.      * short-hand specification for the various formatting properties.
  1175.      * These properties can also be changed individually through the
  1176.      * various setter methods.
  1177.      * <p>
  1178.      * There is no limit to integer digits are set
  1179.      * by this routine, since that is the typical end-user desire;
  1180.      * use setMaximumInteger if you want to set a real value.
  1181.      * For negative numbers, use a second pattern, separated by a semicolon
  1182.      * <P>Example "#,#00.0#" -> 1,234.56
  1183.      * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
  1184.      * a maximum of 2 fraction digits.
  1185.      * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
  1186.      * <p>In negative patterns, the minimum and maximum counts are ignored;
  1187.      * these are presumed to be set in the positive pattern.
  1188.      */
  1189.     public void applyPattern( String pattern ) {
  1190.         applyPattern( pattern, false );
  1191.     }
  1192.  
  1193.     /**
  1194.      * Apply the given pattern to this Format object.  The pattern
  1195.      * is assumed to be in a localized notation. A pattern is a
  1196.      * short-hand specification for the various formatting properties.
  1197.      * These properties can also be changed individually through the
  1198.      * various setter methods.
  1199.      * <p>
  1200.      * There is no limit to integer digits are set
  1201.      * by this routine, since that is the typical end-user desire;
  1202.      * use setMaximumInteger if you want to set a real value.
  1203.      * For negative numbers, use a second pattern, separated by a semicolon
  1204.      * <P>Example "#,#00.0#" -> 1,234.56
  1205.      * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
  1206.      * a maximum of 2 fraction digits.
  1207.      * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
  1208.      * <p>In negative patterns, the minimum and maximum counts are ignored;
  1209.      * these are presumed to be set in the positive pattern.
  1210.      */
  1211.     public void applyLocalizedPattern( String pattern ) {
  1212.         applyPattern( pattern, true );
  1213.     }
  1214.  
  1215.     /**
  1216.      * Does the real work of applying a pattern.
  1217.      */
  1218.     private void applyPattern(String pattern, boolean localized)
  1219.     {
  1220.         char zeroDigit         = PATTERN_ZERO_DIGIT;
  1221.         char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
  1222.         char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
  1223.         char percent           = PATTERN_PERCENT;
  1224.         char perMill           = PATTERN_PER_MILLE;
  1225.         char digit             = PATTERN_DIGIT;
  1226.         char separator         = PATTERN_SEPARATOR;
  1227.         char exponent          = PATTERN_EXPONENT;
  1228.         if (localized) {
  1229.             zeroDigit         = symbols.getZeroDigit();
  1230.             groupingSeparator = symbols.getGroupingSeparator();
  1231.             decimalSeparator  = symbols.getDecimalSeparator();
  1232.             percent           = symbols.getPercent();
  1233.             perMill           = symbols.getPerMill();
  1234.             digit             = symbols.getDigit();
  1235.             separator         = symbols.getPatternSeparator();
  1236.             exponent          = symbols.getExponentialSymbol();
  1237.         }
  1238.         boolean gotNegative = false;
  1239.  
  1240.         decimalSeparatorAlwaysShown = false;
  1241.         isCurrencyFormat = false;
  1242.         useExponentialNotation = false;
  1243.  
  1244.         // Two variables are used to record the subrange of the pattern
  1245.         // occupied by phase 1.  This is used during the processing of the
  1246.         // second pattern (the one representing negative numbers) to ensure
  1247.         // that no deviation exists in phase 1 between the two patterns.
  1248.         int phaseOneStart = 0;
  1249.         int phaseOneLength = 0;
  1250.  
  1251.         int start = 0;
  1252.         for (int j = 1; j >= 0 && start < pattern.length(); --j)
  1253.         {
  1254.             boolean inQuote = false;
  1255.             StringBuffer prefix = new StringBuffer();
  1256.             StringBuffer suffix = new StringBuffer();
  1257.             int decimalPos = -1;
  1258.             int multiplier = 1;
  1259.             int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
  1260.             byte groupingCount = -1;
  1261.  
  1262.             // The phase ranges from 0 to 2.  Phase 0 is the prefix.  Phase 1 is
  1263.             // the section of the pattern with digits, decimal separator,
  1264.             // grouping characters.  Phase 2 is the suffix.  In phases 0 and 2,
  1265.             // percent, permille, and currency symbols are recognized and
  1266.             // translated.  The separation of the characters into phases is
  1267.             // strictly enforced; if phase 1 characters are to appear in the
  1268.             // suffix, for example, they must be quoted.
  1269.             int phase = 0;
  1270.  
  1271.             // The affix is either the prefix or the suffix.
  1272.             StringBuffer affix = prefix;
  1273.  
  1274.             for (int pos = start; pos < pattern.length(); ++pos)
  1275.             {
  1276.                 char ch = pattern.charAt(pos);
  1277.             switch (phase)
  1278.             {
  1279.                 case 0:
  1280.                 case 2:
  1281.                 // Process the prefix / suffix characters
  1282.                 if (inQuote)
  1283.                 {
  1284.                     // A quote within quotes indicates either the closing
  1285.                     // quote or two quotes, which is a quote literal.  That is,
  1286.                     // we have the second quote in 'do' or 'don''t'.
  1287.                     if (ch == QUOTE)
  1288.                     {
  1289.                         if ((pos+1) < pattern.length() &&
  1290.                         pattern.charAt(pos+1) == QUOTE)
  1291.                         {
  1292.                         ++pos;
  1293.                         affix.append(ch); // 'don''t'
  1294.                         }
  1295.                         else
  1296.                         {
  1297.                         inQuote = false; // 'do'
  1298.                         }
  1299.                         continue;
  1300.                     }
  1301.                 }
  1302.                 else
  1303.                 {
  1304.                     // Process unquoted characters seen in prefix or suffix
  1305.                     // phase.
  1306.                     if (ch == digit ||
  1307.                         ch == zeroDigit ||
  1308.                         ch == groupingSeparator ||
  1309.                         ch == decimalSeparator)
  1310.                     {
  1311.                         /* Can't simply throw exception here if (phase == 2); unquoted special
  1312.                          * character; for backward compatibility.  Check
  1313.                          * The international demos of 1.1 for more details.
  1314.                          */
  1315.                         if (phase == 2 && affix.length() > 0)
  1316.                             throw new IllegalArgumentException("Unquoted special character '" +
  1317.                                            ch + "' in pattern \"" +
  1318.                                            pattern + '"');
  1319.                         phase = 1;
  1320.                         if (j == 1) phaseOneStart = pos;
  1321.                         --pos; // Reprocess this character
  1322.                         continue;
  1323.                     }
  1324.                     else if (ch == CURRENCY_SIGN)
  1325.                     {
  1326.                         // Use lookahead to determine if the currency sign is
  1327.                         // doubled or not.
  1328.                         boolean doubled = (pos + 1) < pattern.length() &&
  1329.                         pattern.charAt(pos + 1) == CURRENCY_SIGN;
  1330.                         affix.append(doubled ?
  1331.                              symbols.getInternationalCurrencySymbol() :
  1332.                              symbols.getCurrencySymbol());
  1333.                         if (doubled) ++pos; // Skip over the doubled character
  1334.                         isCurrencyFormat = true;
  1335.                         continue;
  1336.                     }
  1337.                     else if (ch == QUOTE)
  1338.                     {
  1339.                         // A quote outside quotes indicates either the opening
  1340.                         // quote or two quotes, which is a quote literal.  That is,
  1341.                         // we have the first quote in 'do' or o''clock.
  1342.                         if (ch == QUOTE)
  1343.                         {
  1344.                         if ((pos+1) < pattern.length() &&
  1345.                             pattern.charAt(pos+1) == QUOTE)
  1346.                         {
  1347.                             ++pos;
  1348.                             affix.append(ch); // o''clock
  1349.                         }
  1350.                         else
  1351.                         {
  1352.                             inQuote = true; // 'do'
  1353.                         }
  1354.                         continue;
  1355.                         }
  1356.                     }
  1357.                     else if (ch == separator)
  1358.                     {
  1359.                         // Don't allow separators before we see digit characters of phase
  1360.                         // 1, and don't allow separators in the second pattern (j == 0).
  1361.                         if (phase == 0 || j == 0)
  1362.                         throw new IllegalArgumentException("Unquoted special character '" +
  1363.                                            ch + "' in pattern \"" +
  1364.                                            pattern + '"');
  1365.                         start = pos + 1;
  1366.                         pos = pattern.length();
  1367.                         continue;
  1368.                     }
  1369.  
  1370.                     // Next handle characters which are appended directly.
  1371.                     else if (ch == percent)
  1372.                     {
  1373.                         if (multiplier != 1)
  1374.                         throw new IllegalArgumentException("Too many percent/permille characters in pattern \"" +
  1375.                                            pattern + '"');
  1376.                         multiplier = 100;
  1377.                         ch = symbols.getPercent();
  1378.                     }
  1379.                     else if (ch == perMill)
  1380.                     {
  1381.                         if (multiplier != 1)
  1382.                         throw new IllegalArgumentException("Too many percent/permille characters in pattern \"" +
  1383.                                            pattern + '"');
  1384.                         multiplier = 1000;
  1385.                         ch = symbols.getPerMill();
  1386.                     }
  1387.                 }
  1388.                 // Note that if we are within quotes, or if this is an unquoted,
  1389.                 // non-special character, then we usually fall through to here.
  1390.                 affix.append(ch);
  1391.                 break;
  1392.             case 1:
  1393.                 // Phase one must be identical in the two sub-patterns.  We
  1394.                 // enforce this by doing a direct comparison.  While
  1395.                 // processing the first sub-pattern, we just record its
  1396.                 // length.  While processing the second, we compare
  1397.                 // characters.
  1398.                 if (j == 1) ++phaseOneLength;
  1399.                 else
  1400.                 {
  1401.                     /* Can't throw exception if (ch != pattern.charAt(phaseOneStart++); subpattern
  1402.                      * mismatch; for backward compatibility.  Check
  1403.                      * The international demos of 1.1 for more details.  HShih
  1404.                      */
  1405.                     if (--phaseOneLength == 0)
  1406.                     {
  1407.                         phase = 2;
  1408.                         affix = suffix;
  1409.                     }
  1410.                     continue;
  1411.                 }
  1412.  
  1413.                 // Process the digits, decimal, and grouping characters.  We
  1414.                 // record five pieces of information.  We expect the digits
  1415.                 // to occur in the pattern ####0000.####, and we record the
  1416.                 // number of left digits, zero (central) digits, and right
  1417.                 // digits.  The position of the last grouping character is
  1418.                 // recorded (should be somewhere within the first two blocks
  1419.                 // of characters), as is the position of the decimal point,
  1420.                 // if any (should be in the zero digits).  If there is no
  1421.                 // decimal point, then there should be no right digits.
  1422.                 if (ch == digit)
  1423.                 {
  1424.                     if (zeroDigitCount > 0) ++digitRightCount; else ++digitLeftCount;
  1425.                     if (groupingCount >= 0 && decimalPos < 0) ++groupingCount;
  1426.                 }
  1427.                 else if (ch == zeroDigit)
  1428.                 {
  1429.                     if (digitRightCount > 0)
  1430.                        throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
  1431.                                        pattern + '"');
  1432.                     ++zeroDigitCount;
  1433.                     if (groupingCount >= 0 && decimalPos < 0) ++groupingCount;
  1434.                 }
  1435.                 else if (ch == groupingSeparator)
  1436.                 {
  1437.                     groupingCount = 0;
  1438.                 }
  1439.                 else if (ch == decimalSeparator)
  1440.                 {
  1441.                     if (decimalPos >= 0)
  1442.                         throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
  1443.                                        pattern + '"');
  1444.                     decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
  1445.                 }
  1446.                 // Fix for bugid 4112390.  Exponent support is a new feature
  1447.                 // and should not be a part of 1.1.6 release. Disable it.
  1448.                 else if (false /*ch == exponent*/)
  1449.                 {
  1450.                     if (useExponentialNotation)
  1451.                         throw new IllegalArgumentException("Multiple exponential " +
  1452.                                        "symbols in pattern \"" +
  1453.                                        pattern + '"');
  1454.                     useExponentialNotation = true;
  1455.                     minExponentDigits = 0;
  1456.  
  1457.                     // Use lookahead to parse out the exponential part of the
  1458.                     // pattern, then jump into phase 2.
  1459.                     while (++pos < pattern.length() &&
  1460.                            pattern.charAt(pos) == zeroDigit)
  1461.                     {
  1462.                         ++minExponentDigits;
  1463.                         ++phaseOneLength;
  1464.                     }
  1465.  
  1466.                     if ((digitLeftCount + zeroDigitCount) < 1 ||
  1467.                         minExponentDigits < 1)
  1468.                         throw new IllegalArgumentException("Malformed exponential " +
  1469.                                            "pattern \"" +
  1470.                                            pattern + '"');
  1471.  
  1472.                     // Transition to phase 2
  1473.                     phase = 2;
  1474.                     affix = suffix;
  1475.                     --pos;
  1476.                     continue;
  1477.                 }
  1478.                 else
  1479.                 {
  1480.                     phase = 2;
  1481.                     affix = suffix;
  1482.                     --pos;
  1483.                     --phaseOneLength;
  1484.                     continue;
  1485.                 }
  1486.                 break;
  1487.             }
  1488.         }
  1489.  
  1490.         // Handle patterns with no '0' pattern character.  These patterns
  1491.         // are legal, but must be interpreted.  "##.###" -> "#0.###".
  1492.         // ".###" -> ".0##".
  1493.         if (zeroDigitCount == 0 && digitLeftCount > 0)
  1494.         {
  1495.             if (decimalPos >= 0) // Handle "###.###" and "###." and ".###"
  1496.             {
  1497.                 int n = decimalPos;
  1498.                 if (n == 0) ++n; // Handle ".###"
  1499.                 digitRightCount = digitLeftCount - n;
  1500.                 digitLeftCount = n - 1;
  1501.             }
  1502.             else --digitLeftCount; // Handle "###"
  1503.             zeroDigitCount = 1;
  1504.         }
  1505.  
  1506.         // Do syntax checking on the digits.
  1507.         if ((decimalPos < 0 && digitRightCount > 0) ||
  1508.         (decimalPos >= 0 &&
  1509.          (decimalPos < digitLeftCount ||
  1510.           decimalPos > (digitLeftCount + zeroDigitCount))) ||
  1511.         groupingCount == 0 ||
  1512.         inQuote)
  1513.             throw new IllegalArgumentException("Malformed pattern \"" +
  1514.                                pattern + '"');
  1515.  
  1516.             if (j == 1) {
  1517.                 this.positivePrefix = prefix.toString();
  1518.                 this.positiveSuffix = suffix.toString();
  1519.                 this.negativePrefix = positivePrefix;   // assume these for now
  1520.                 this.negativeSuffix = positiveSuffix;
  1521.             int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
  1522.             /* The effectiveDecimalPos is the position the decimal is at or
  1523.              * would be at if there is no decimal.  Note that if decimalPos<0,
  1524.              * then digitTotalCount == digitLeftCount + zeroDigitCount.  */
  1525.             int effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
  1526.             setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
  1527.             setMaximumIntegerDigits(useExponentialNotation ?
  1528.                         digitLeftCount + getMinimumIntegerDigits() : 127);
  1529.             setMaximumFractionDigits(decimalPos >= 0 ? (digitTotalCount - decimalPos) : 0);
  1530.             setMinimumFractionDigits(decimalPos >= 0 ?
  1531.                          (digitLeftCount + zeroDigitCount - decimalPos) : 0);
  1532.             setGroupingUsed(groupingCount > 0);
  1533.             this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
  1534.             this.multiplier = multiplier;
  1535.             setDecimalSeparatorAlwaysShown(decimalPos == 0 || decimalPos == digitTotalCount);
  1536.             } else {
  1537.                 this.negativePrefix = prefix.toString();
  1538.                 this.negativeSuffix = suffix.toString();
  1539.                 gotNegative = true;
  1540.             }
  1541.         }
  1542.  
  1543.     // If there was no negative pattern, or if the negative pattern is identical
  1544.     // to the positive pattern, then prepend the minus sign to the positive
  1545.     // pattern to form the negative pattern.
  1546.         if (!gotNegative ||
  1547.             (negativePrefix.equals(positivePrefix)
  1548.              && negativeSuffix.equals(positiveSuffix))) {
  1549.             negativeSuffix = positiveSuffix;
  1550.             negativePrefix = symbols.getMinusSign() + negativePrefix;
  1551.         }
  1552.     }
  1553.  
  1554.     /**
  1555.      * Override readObject.
  1556.      */
  1557.     private void readObject(ObjectInputStream stream)
  1558.          throws IOException, ClassNotFoundException
  1559.     {
  1560.         stream.defaultReadObject();
  1561.         digitList = new DigitList();
  1562.     }
  1563.  
  1564.     //----------------------------------------------------------------------
  1565.     // INSTANCE VARIABLES
  1566.     //----------------------------------------------------------------------
  1567.  
  1568.     private transient DigitList digitList = new DigitList();
  1569.  
  1570.     // these are often left as localized
  1571.     private String  positivePrefix = "";
  1572.     private String  positiveSuffix = "";
  1573.     private String  negativePrefix = "-";
  1574.     private String  negativeSuffix = "";
  1575.     private int     multiplier = 1;
  1576.     private byte    groupingSize = 3;  // invariant, > 0 if useThousands
  1577.     private boolean decimalSeparatorAlwaysShown = false;
  1578.     private transient boolean isCurrencyFormat = false;
  1579.     private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
  1580.  
  1581.  
  1582.     // These fields were added to allow support of exponential notation.
  1583.     // Unfortunately, this feature should not have been added to the 1.1.6
  1584.     // release (see bugid 4112390).  Rather than trying to expunge the
  1585.     // offending code, we've simply disabled it.  These fields must remain
  1586.     // but they need to be transient so as not to affect the persistent
  1587.     // state.  Note that the default initializations are sufficient for these
  1588.     // fields.
  1589.     private transient boolean useExponentialNotation;  // New to JDK 1.1.6
  1590.     private transient byte    minExponentDigits;       // New to JDK 1.1.6
  1591.  
  1592.     //----------------------------------------------------------------------
  1593.  
  1594.     //----------------------------------------------------------------------
  1595.     // CONSTANTS
  1596.     //----------------------------------------------------------------------
  1597.  
  1598.     // Constants for characters used in programmatic (unlocalized) patterns.
  1599.     private static final char       PATTERN_ZERO_DIGIT         = '0';
  1600.     private static final char       PATTERN_GROUPING_SEPARATOR = ',';
  1601.     private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
  1602.     private static final char       PATTERN_PER_MILLE          = '\u2030';
  1603.     private static final char       PATTERN_PERCENT            = '%';
  1604.     private static final char       PATTERN_DIGIT              = '#';
  1605.     private static final char       PATTERN_SEPARATOR          = ';';
  1606.     private static final char       PATTERN_EXPONENT           = 'E';
  1607.  
  1608.     /**
  1609.      * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
  1610.      * is used in patterns and substitued with either the currency symbol,
  1611.      * or if it is doubled, with the international currency symbol.  If the
  1612.      * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
  1613.      * replaced with the monetary decimal separator.
  1614.      *
  1615.      * The CURRENCY_SIGN is not localized.
  1616.      */
  1617.     private static final char       CURRENCY_SIGN = '\u00A4';
  1618.  
  1619.     private static final char       QUOTE = '\'';
  1620.  
  1621.     // Proclaim JDK 1.1 serial compatibility.
  1622.     static final long serialVersionUID = 864413376551465018L;
  1623.  
  1624.     /**
  1625.      * Cache to hold the NumberPattern of a Locale.
  1626.      */
  1627.     private static Hashtable cachedLocaleData = new Hashtable(3);
  1628. }
  1629.  
  1630. //eof
  1631.